package games.checkers;

import games.checkers.boardView.miniBoard;
import games.checkers.chipPath.pathNode;
import games.checkers.gameColors.colorScheme;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class chipManager 
{
	private checkers program; 
	private gameAI ai;
	private int level;
	private ArrayList<chip> p1chips = new ArrayList<chip>(0);
	private ArrayList<chip> p2chips = new ArrayList<chip>(0);
	
	public static byte player1 = -1;
	public static byte player2 = 1;
	private byte player;
	private int totalMoves;
	private ArrayList<pathNode> previousPath;
	private int [] previousBoard;
	private boardView previousMove;
	private boolean huffing = true;
	private boolean appliedHuffing = false;
	
	private ArrayList<pathNode> AIpath;
	private ArrayList<ArrayList<pathNode>> validPaths = new ArrayList<ArrayList<pathNode>>(0);
	
	public chipManager(checkers prog)
	 {
		program = prog;
		ai = new gameAI(prog);
		level = gameAI.NORMAL;
		
	 }

	public void reset()
	{
		totalMoves = 0;
		checkersBoard board = program.getBoard();
		colorScheme colors = program.colorScheme();
		Color p1color = colors.player1;
		Color p2color = colors.player2;
		p1chips.clear();
		p2chips.clear();
		chipBin redBin = program.redBin();
		chipBin whiteBin = program.whiteBin();
		 for (int a=0; a<12; a++)
		 {	 
			 p1chips.add(new chip(a,48,p1color,player2,board,this,redBin));
			 p2chips.add(new chip(31-a,48,p2color,player1,board,this,whiteBin));
		 }
		 player = player1;
		 generateMoves();
		 program.getBoard().refresh();
		 
		 if (previousMove != null) previousMove.dispose();
		 previousMove = new boardView(program);
		 
		 AImove();
	}
	
	public void setColors(colorScheme c)
	{
		if (p1chips.size() == 0) return;
		for (int a=0; a<12; a++)
		 {	 
			 ((chip) p1chips.get(a)).setColor(c.player1);
			 ((chip) p2chips.get(a)).setColor(c.player2);
		 }
	}
	
	public void huffing(int h)
	{
		if (h == 0) huffing = true;
		else huffing = false;
	}
	
	public ArrayList<chip> getRedChips()
	 {
		 return p1chips;
	 }
	 
	 public ArrayList<chip> getWhiteChips()
	 {
		 return p2chips;
	 }
	 
	 public chip chipOnTile(int t)
	 {
		 if (t < 0) return null;
		 if (p1chips.size() == 0) return null;
		 
		 chip c = null;
		 chip rChip;
		 chip wChip;
		
		for (int i=11; i>=0; --i)
		{
			rChip = (chip) p1chips.get(i);
			if (rChip.getTile() == t) return rChip;
			wChip = (chip) p2chips.get(i);
			if (wChip.getTile() == t) return wChip;
		}
		 
		 return c;
	 }
	 
	 public void moveChipToTile(chip c, int t)
	 {
		 if (c == null) return;
		 if (c.getTile() == t) return;
		 if (chipOnTile(t) != null)
		 {
			 c.setTile(c.getTile());
			 return;
		 }
		 c.setTile(t);
		 if (player == player1) player = player2;
		 else player = player1;
		 
		 ++totalMoves;
		 System.out.println("Move #: "+String.valueOf(totalMoves));
		 
		 program.getBoard().refresh();
		 
//		 switch (program.numberPlayers())
//		 {
//		 case 0: if (player != player1) AImove(); break;
//		 case 1: break;
//		 default: break;
//		 }
//		 AImove();
		 //appliedHuffing = false;
	 }
	 
	 public void animateChipToTile(chip c, int t)
	 {
		 Point p1 = program.getBoard().getTilePosition(t);
		 if (c == null) return;
		 Point p2 = program.getBoard().getTilePosition(c.getTile());
		 float step = 5;
		 float xdist = (p2.x - p1.x)/step;
		 float ydist = (p2.y - p1.y)/step;
		 Point z = (Point) p2.clone();
		 
		 for (int i=0; i < step; i++)
		 {
			 z.x -= xdist;
			 z.y -= ydist;
			 c.moveTo(z);
			 program.getBoard().refresh();
			 program.redBin().repaint();
			 program.whiteBin().repaint();
		 }
		 
	 }
	 
	 public void applyPath(ArrayList<pathNode> path)
	 {
		 boolean jumpingInPath = false;
		 pathNode node;
		 int startTile = 0;
		 
		 if (totalMoves > 0)
		 {
			if (previousMove != null) previousMove.updateBoard(previousBoard, previousPath); 
		 }
		 previousBoard = boardArray();
		 previousPath = path;
		 
		 if (totalMoves > 0)
		 {
			previousMove.updateBoard(previousBoard, previousPath); 
		 }
		 
		 //check for game over status
		 if ((path == null) || (path.size() == 0)) 
		 {
			 gameOver();
			 return;
		 }
		 
		 //need state of board before move for huffing calculation later 
		 int [] previousBoard = boardArray();
		 ArrayList<ArrayList<pathNode>> allPaths = chipPath.findAllPaths(player, previousBoard, program.getBoard(), this);
		 
		 //apply the path.
		 for (int n=0;n<path.size();n++)
		{
			node = path.get(n);
			
			switch(node.action)
			{
			case chipPath.start: startTile = node.tile; break;
			case chipPath.cell: 
			{
				//if (path.size() == 3) break;
				//animateChipToTile(chipOnTile(startTile),node.tile); 
				//startTile = node.tile; 
//				moveChipToTile(chipOnTile(startTile),node.tile);
//				startTile = node.tile;
				break;
			}
			case chipPath.jumpLeft: chipOnTile(node.tile).jumpMe(); jumpingInPath = true; break;
			case chipPath.jumpRight: chipOnTile(node.tile).jumpMe(); jumpingInPath = true; break;
			case chipPath.end:  
				{
					//animateChipToTile(chipOnTile(startTile),node.tile); 
					moveChipToTile(chipOnTile(startTile),node.tile);
					break;
				}
			default: break;
			}
		}
		 
		 //if huffing rule is enabled:
		 //check all paths to see if a jump was present.
		 //if so, then if the path used did not have a jump, 
		 //then remove the chip from the first path with a jump.
		 if ((huffing) && (!jumpingInPath))
		 {
			 boolean pathWithJumps = false;
			 ArrayList<pathNode> otherPath = new ArrayList<pathNode>(0);
			 //ArrayList<ArrayList<pathNode>> allPaths = chipPath.findAllPaths(player, previousBoard, program.getBoard(), this);
			 for (int p=0;p<allPaths.size();p++)
			 {
				 otherPath = allPaths.get(p);
				 for (int n=1;n<otherPath.size()-2;n++)
				 {
					 node = otherPath.get(n);
					 if ((node.action == chipPath.jumpLeft) || (node.action == chipPath.jumpRight))
					 {
						 pathWithJumps = true;
						 break;
					 }
				 }
				 if (pathWithJumps) break;
			 }
			 
			 if (pathWithJumps) // && !appliedHuffing) 
			 {
				 //appliedHuffing = true;
				 pathNode otherNode = otherPath.get(0);
				 chip otherChip = chipOnTile(otherNode.tile);
				 if (otherChip == null)
				 {
//					 chip oneMoreChip = chipOnTile(path.get(path.size()-1).tile);
//					 if (oneMoreChip != null) oneMoreChip.jumpMe();;
					 return;
				 }
				 applyHuffingRule(otherPath,previousBoard);
			 }
		 } 
		
		 AImove();
	 }
	 
	 private void applyHuffingRule(ArrayList<pathNode> path,int[] previousBoard)
	 { 
		 //show message to user		 
		 JPanel huffPanel = new JPanel();
		 huffPanel.setLayout(new BoxLayout(huffPanel, BoxLayout.Y_AXIS));
		 miniBoard board1 = new boardView.miniBoard();
		 board1.setPreferredSize(new Dimension(256,256));
		 board1.setBackground(new Color(240,220,130));
		 board1.updateBoard(previousBoard, path);
		 huffPanel.add(board1);
		 huffPanel.add(new JTextArea("You failed to make a jump.  You've been Huffed!"));
		 
		 JOptionPane.showMessageDialog(program, huffPanel, "Huffing Rule", JOptionPane.PLAIN_MESSAGE); 
		 
		 //remove their chip from the board.
		 chipOnTile(path.get(0).tile).jumpMe();
	 }
	 
	 private void AImove()
	 {
		 AIpath = ai.generateMove(boardArray(), player, level);
		 //System.out.println("numplayers : "+program.numberPlayers() + "player: "+player);
		 if (program.numberPlayers() == 1) return;
		 if ((program.numberPlayers() == 0) && (player == player1)) return;
		 
		 if (AIpath == null) gameOver();
		 
		 applyPath(AIpath);
		 
			program.getBoard().refresh();
			program.redBin().repaint();
			program.whiteBin().repaint();
	 }
	 
	 public byte currentPlayer()
	 {
		 return player;
	 }
	 
	 public void generateMoves()
	 {	 
		 validPaths.clear();
		 
		 validPaths = chipPath.findAllPaths(player, boardArray(), program.getBoard(), this);
		 
		 if (validPaths.size() == 0) gameOver();
			 
		 program.getBoard().setValidMoves(validPaths, false);
	 }
	 
	 public ArrayList<ArrayList<pathNode>> validPaths()
	 {
		 return validPaths;
	 }
	 
	 public int [] boardArray()
	 {
		 int [] board = new int[32];
		 chip aChip;
		 if (p1chips.size() == 0) return board;
		 for (int c=11; c >= 0; --c)
		 {
			 aChip =  p1chips.get(c);
			 if ((aChip != null) && aChip.onBoard())
			 {
				if (aChip.isKing()) board[aChip.getTile()] = 4; else board[aChip.getTile()] = 1;
			 }
			 aChip =  p2chips.get(c);
			 if (aChip != null)
				 if ((aChip != null) && aChip.onBoard())
				 {
					if (aChip.isKing()) board[aChip.getTile()] = -4; else board[aChip.getTile()] = -1;
				 }
		 }
			 
		 return board;
	 }
	 
	 public void gameAI(int g)
	 {
		 switch(g)
		{
			case 0: level = gameAI.EASY; break;
			case 1: level = gameAI.NORMAL; break;
			case 2: level = gameAI.HARD; break;
			default: level = gameAI.EASY; break;
		}

	 }
	 
	 public void suggest()
	 {
		 ArrayList<ArrayList<pathNode>> suggestPath = new  ArrayList<ArrayList<pathNode>>(0);
		 suggestPath.add(AIpath);
		 program.getBoard().setValidMoves(suggestPath, true);
	 }
	 
	 public void gameOver()
	 {
		 if (totalMoves == 0) return;
		 
		 program.getBoard().refresh();
		 
		 String message = "";
		 colorScheme scheme = program.colorScheme();
		 if (player == player2) message = scheme.name2+" Wins";
		 else message = scheme.name1+" Wins";
		 
		 message += " in "+String.valueOf(totalMoves)+" moves.";
		 
		 JOptionPane.showMessageDialog(program, message, "Game Over", JOptionPane.PLAIN_MESSAGE);
		 program.newGame();
	 }
	 
}
